#include "serverConn.h"





#include "asio.hpp"
#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>

#include "user.h"
#include "userMgr.h"

ServerConn::~ServerConn(){
    UserMgr::Inst()->unregConn( this);
    _socket.close(); 
    printf("connnection destroy!\n"); 
}

ServerConn::ServerConn(asio::io_service& io_service)
    : _socket(io_service)
{ 
    _connID = UserMgr::Inst()->regConn( this);
    memset( _msg, 0, 4096);
}



void ServerConn::start()
{
    _socket.async_read_some(asio::buffer(_msg),
            boost::bind(&ServerConn::handle_read, shared_from_this(),
                asio::placeholders::error,
                asio::placeholders::bytes_transferred));
}


int ServerConn::sendMsg( MsgInfo* rsp){ 
    //UserMgr::Inst();

    memset( _msg, 0, 4096);
    uint32_t header = 0x6767dfef;
    memcpy( _msg, (void*)&header, sizeof(uint32_t));
    char* data = &_msg[20];
    SSMAP & map = rsp->info;

    unsigned short num = map.size();
    memcpy( data, (void*)&num, sizeof(unsigned short));
    data+=sizeof(unsigned short);

    SSMAP::iterator it(map.begin()), end(map.end());
    for ( ; it!=end; ++it){
        const std::string& key = it->first;
        unsigned short ksz = key.size();
        const std::string& val = it->second;
        unsigned short vsz = val.size();
        memcpy(data, &ksz, sizeof(unsigned short));
        data+=sizeof(unsigned short);
        memcpy(data, key.c_str(), ksz);
        data+=ksz;
        memcpy(data, &vsz, sizeof(unsigned short));
        data+=sizeof(unsigned short);
        memcpy(data, val.c_str(), vsz);
        data+=vsz;
        printf("key: %s, val: %s, valint: %d \n", key.c_str(), val.c_str(), val.c_str());
    }

    size_t sz = data - &_msg[20];
    printf("send msg out size: %d ", sz);
    setMsgLength(sz+12);
    setMsgType(rsp->msgType);
    showHex( (unsigned char*)_msg, sz+20);
    asio::async_write( _socket, asio::buffer( _msg, sz+20) ,
        boost::bind(&ServerConn::handle_write, shared_from_this(),
            asio::placeholders::error,
            asio::placeholders::bytes_transferred));
    return sz;
}

void ServerConn::handle_write(const asio::error_code& /* error*/, size_t size)
{ 
    printf( "write out size: %d\n" , size );
    _socket.async_read_some(asio::buffer(_msg),
            boost::bind(&ServerConn::handle_read, shared_from_this(),
                asio::placeholders::error,
                asio::placeholders::bytes_transferred));
}

void ServerConn::handle_read(const asio::error_code& error, size_t  bytes_transferred)
{ 

    if ( error){
        printf("**error: %s\n",error.message().c_str());
        return ;
    }

    //printf ( "got msg: %s\n" , _msg );
    if( strcmp ( _msg , "<policy-file-request/>") == 0 ) {
        static const char *message = "<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"8000\"/></cross-domain-policy>";//套接字策略文件  
        printf("write flash response message: %s\n" , message );
        asio::async_write(_socket, asio::buffer(message, strlen(message) ),
                boost::bind(&ServerConn::handle_write, shared_from_this(),
                    asio::placeholders::error,
                    asio::placeholders::bytes_transferred));
    }
    else{
        if(parseData((unsigned char*) _msg, bytes_transferred) ){
        }
    }
}

void ServerConn::setMsgType( uint32_t msgType){
    //unsigned short msgID = msgType;
    //unsigned short msgT= msgType>>16;
    memcpy( &_msg[16], &msgType, 4);
    //memcpy( &_msg[18], &msgID, 2);
}
void ServerConn::setMsgLength( size_t sz){
    memcpy( &_msg[4], &sz, 4);
}

bool ServerConn::parseDataMap( unsigned char* rb, size_t sz ){
    unsigned short num =0, pos=0;;
    memcpy( &num, rb, 2);
    pos+=2;
    //printf( "map num: %d\n", num);

    unsigned short keysz, valsz;
    char key[256];
    char val[256];
    _info.info.clear();
    while ( num > 0 && pos<sz ){
        memset(key, 0, 256);
        memset(val, 0, 256);
        memcpy( &keysz, rb+pos, 2);
        pos+=2;
        memcpy( &key, rb+pos, keysz);
        pos+=keysz;
        memcpy( &valsz, rb+pos, 2);
        pos+=2;
        memcpy( &val, rb+pos, valsz);
        pos+=valsz;

        std::string & v = _info.info[key];
        v.assign( val, valsz);
        printf("key: %s, val: %s, valint: %d\n", key, val, val);
        --num;
    }
    //printf("connID: %d, msginfo pointer: %d\n", _connID, &_info);
    UserMgr::Inst()->onMsgReq( &_info, _connID);
    return true;
}

bool ServerConn::parseData( unsigned char* rb, size_t sz ){
    //printf (" str len: %d\n" , strlen( (char*)rb) );
    printf("got str from client: ");
    showHex( rb, sz);

    unsigned short msgType = 0, msgID=0;
    msgID= *(unsigned short*)(rb+16);
    msgType = *(unsigned short*)(rb+18);

    _info.msgType = msgType<<16|msgID;
    //printf( "\nmsg type: %d %d: %d\n", msgType , msgID);
    
    parseDataMap( &rb[20], sz-20);
    return true;
}

bool ServerConn::showHex( unsigned char* rb, size_t sz){
    size_t i  = 0;
    while( i < 4 ){
        unsigned char show = 0 | rb[i];
        printf( "|%x", show);
        ++i;
    }
    if ( rb[0] != 0xef || rb[1] != 0xdf || rb[2] !=0x67 || rb[3] != 0x67){
        printf( "wrong header\n");
        return false;
    }
    size_t len = 0;
    while( i < 8 ){
        len |= (rb[i] << ( i -4 ) );
        printf( "|%2x", rb[i]);
        ++i;
    }
    if ( sz != len+8){
        printf( "wrong size\n");
        return false;
    }
    len += 8;
    while( i < len ){
        printf( "|%2x", rb[i]);
        ++i;
    }
    printf( "\n");
    return true;
}
